#ifndef __BUFFER_HPP__
#define __BUFFER_HPP__

#include <iostream>
#include <vector>
#include <string>
#include <cstdint>
#include <cstring>
#include <cassert>

static const int buffer_default_size = 1024; // 缓冲区默认大小
class Buffer
{
private:
    char *Begin() const
    {
        return (char*)&(*_buffer.begin());
    }

    /* 获取当前前沿空闲空间大小——写位置之后的空闲空间（前：操作靠前） */
    uint64_t TailIdleSize() const
    {
        return _buffer.size() - _write_index;
    }
    /* 获取当前后沿空闲空间大小——读位置之前的空闲空间（后：操作靠后） */
    uint64_t HeadIdleSize() const
    {
        return _read_index;
    }

    /* 确保可写——移动+扩容 */
    void EnsureWriteAble(uint64_t len)
    {
        // 1. 尾部空闲空间足够，直接返回true
        if (TailIdleSize() >= len)
            return;
        // 2. 总的空闲空间足够，将数据前移，然后返回
        if (TailIdleSize() + HeadIdleSize() >= len)
        {
            uint64_t ras = ReadAbleSize();
            std::copy(ReadPosition(), ReadPosition() + ras, Begin());
            _read_index = 0;
            _write_index = ras;
            return;
        }
        // 3. 总的空闲空间不够，需要扩容
        _buffer.resize(_write_index + len);
        return;
    }

    /* 查找换行符 */
    char *FindCRLF()
    {
        const void *res = memchr(ReadPosition(), '\n', ReadAbleSize());
        return (char *)res;
    }
public:
    Buffer() : _read_index(0), _write_index(0), _buffer(buffer_default_size)
    {
    }

    /* 获取当前写入位置 */
    char *WritePosition()
    {
        return Begin() + _write_index;
    }
    /* 获取当前读取位置 */
    char *ReadPosition() const
    {
        return Begin() + _read_index;
    }
    /* 获取当前可读数据大小 */
    uint64_t ReadAbleSize() const
    {
        return _write_index - _read_index;
    }
    /* 读位置后移 */
    void MoveReadOffset(uint64_t len)
    {
        assert(len <= ReadAbleSize()); // 向后移动大小必须不大于可读数据大小
        _read_index += len;
    }
    /* 写位置后移 */
    void MoveWriteOffset(uint64_t len)
    {
        assert(len <= TailIdleSize()); // 数据只会向后插入，所以向后移动大小必须不大于后置空闲空间大小
        _write_index += len;
    }

    /* 写入数据 */
    void Write(const void *data, uint64_t len)
    {
        if(len == 0) return;// 保证写入有效数据

        // 1. 保证有足够的空闲空间
        EnsureWriteAble(len);
        // 2. 拷贝数据
        const char *d = (const char *)data; // void* 类型是没有步长的
        std::copy(d, d + len, WritePosition());
        // 3. 移动写偏移
        MoveWriteOffset(len);
        return;
    }
    void WriteString(const std::string &data)
    {
        return Write(data.c_str(), data.size());
    }
    void WriteBuffer(const Buffer &data)
    {
        return Write(data.ReadPosition(), data.ReadAbleSize());
    }
    /* 读取数据 */
    void Read(void *buffer, uint64_t len)
    {
        assert(len <= ReadAbleSize());

        if(len == 0) return;

        const char *buf = (const char *)buffer;
        std::copy(ReadPosition(), ReadPosition() + len, (char *)buf);
        return;
    }
    /* 读取数据并将这些数据弹出 */
    void ReadAndPop(void *buffer, uint64_t len)
    {
        Read(buffer, len);
        MoveReadOffset(len);
    }
    std::string ReadAsString(uint64_t len)
    {
        assert(len <= ReadAbleSize());
        std::string str;
        str.resize(len);
        Read(&str[0], len);
        return str;
    }
    std::string ReadAsStringAndPop(uint64_t len)
    {
        std::string str = ReadAsString(len);
        MoveReadOffset(len);
        return str;
    }

    /* 清空缓冲区 */
    void Clear()
    {
        _read_index = _write_index = 0; // 逻辑删除
    }

    /* 获取一行数据 */
    std::string GetLine()
    {
        const char *pos = FindCRLF();
        if (pos == nullptr)
            return "";

        return ReadAsString(pos - ReadPosition() + 1); // +1是为了把换行符也取出
    }
    std::string GetLineAndPop()
    {
        std::string str = GetLine();
        MoveReadOffset(str.size());
        return str;
    }

private:
    std::vector<char> _buffer; // 缓冲区
    /* 写入位置和读取位置都是相对位置，相对_buffer首地址的偏移量，考虑到缓冲区可能会比较大，所以是uint64_t类型 */
    uint64_t _read_index;  // 读取位置的偏移量
    uint64_t _write_index; // 写入位置的偏移量
};


#endif